package br.com.financeiro.dao;

import java.io.Serializable;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;

public abstract class GenericDAO<T> implements Serializable {

	/**
	 * serial
	 */
	private static final long serialVersionUID = 1L;

	private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("FinanceiroWeb");
	
	private EntityManager em;
	
	private Class<T> entityClass;
	
	public void beginTransation(){
		em = emf.createEntityManager();
		em.getTransaction().begin();
	}
	
	public void commit(){
		em.getTransaction().commit();
	}
	
	public void rollback(){
		em.getTransaction().rollback();
	}
	
	public void closeTransaction(){
		em.close();
	}
	
	public void commitAndCloseTransaction(){
		commit();
		closeTransaction();
	}
	
	public void flush(){
		em.flush();
	}
	
	public void joinTransaction(){
		em = emf.createEntityManager();
		em.joinTransaction();
	}
	
	public GenericDAO(Class<T> entityClass) {
        this.entityClass = entityClass;
    }
	
	public void save(T entity) {
        em.persist(entity);
    }
 
    public void delete(T entity) {
        T entityToBeRemoved = em.merge(entity);
 
        em.remove(entityToBeRemoved);
    }
 
    public T update(T entity) {
        return em.merge(entity);
    }
 
    public T find(int entityID) {
        return em.find(entityClass, entityID);
    }
 
    public T findReferenceOnly(int entityID) {
        return em.getReference(entityClass, entityID);
    }
     
    protected T findOneResult(String namedQuery, Map<String, Object> parameters) {
        T result = null;
 
        try {
            Query query = em.createNamedQuery(namedQuery);
 
            // Method that will populate parameters if they are passed not null and empty
            if (parameters != null && !parameters.isEmpty()) {
                populateQueryParameters(query, parameters);
            }
 
            result = (T) query.getSingleResult();
 
        } catch (NoResultException e) {
            System.out.println("No result found for named query: " + namedQuery);
        } catch (Exception e) {
            System.out.println("Error while running query: " + e.getMessage());
            e.printStackTrace();
        }
 
        return result;
    }
 
    private void populateQueryParameters(Query query, Map<String, Object> parameters) {
        for (Entry<String, Object> entry : parameters.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
    }
}
